/**
 * 
 */
package com.cipe.cmrs.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.cipe.cmrs.bean.DonorAwardBean;
import com.cipe.cmrs.exception.NonUniqueDonorAwardNumberException;
import com.cipe.cmrs.model.Donor;
import com.cipe.cmrs.model.Donoraward;
import com.cipe.cmrs.model.Donorawardmodification;
import com.cipe.cmrs.model.Donorawardstatus;
import com.cipe.cmrs.model.Modificationtype;
import com.cipe.cmrs.model.User;
import com.cipe.cmrs.util.Constants;
import com.cipe.cmrs.util.DateUtil;
import com.cipe.cmrs.util.DateUtil2;
import com.cipe.cmrs.util.NumberUtil;
import com.cipe.cmrs.util.Util;

/**
 * @author Incepio
 */
@Service
@Transactional
public class DonorawardService extends BaseService<Donoraward> {

	@Autowired
	private UserService userService;
	@Autowired
	private DonorService donorService;
	@Autowired
	private ModificationTypeService modificationTypeService;
	@Autowired
	private DonorawardstatusService donorawardstatusService;

	public List<Donoraward> findDonoraward(Donoraward donoraward) {
		List<Donoraward> donorawardList = new ArrayList<Donoraward>();
		try {
			// FIXME create query
			String query = "from Donoraward where" + Util.createlikeFirstQueryClause("donorAwardNumber", donoraward.getDonorAwardNumber())
					+ Util.createQueryClause(donoraward.getDonor())
					+ Util.createQueryClause("donorawardstatus.id", donoraward.getDonorawardstatus().getId())
					+ Util.createOrderByDesc("enddate");
			logger.debug("QUERY:" + query);
			donorawardList = dao.getResultList(query);
		} catch (Exception exp) {
			logger.warn(exp.toString());
		}
		return donorawardList;
	}

	public List<Donoraward> findDonoraward(String procedure) {
		return this.dao.getResultListWithNativeQuery(procedure, Donoraward.class);
	}

	public List<Donoraward> findDonorawardByDonorAwardNumber(String donorawardNumber) {
		List<Donoraward> donorawardList = new ArrayList<Donoraward>();
		try {
			String query = "from Donoraward where donorAwardNumber = '" + donorawardNumber.trim() + "'";
			logger.debug("QUERY:" + query);
			donorawardList = dao.getResultList(query);
		} catch (Exception exp) {
			logger.warn(exp.toString());
		}
		return donorawardList;
	}

	@Transactional(readOnly = true)
	public DonorAwardBean getDonorAward(Integer id) {
		Assert.notNull(id);
		DonorAwardBean result = null;
		Donoraward donorAward = findById(id);
		if (donorAward != null) {
			result = new DonorAwardBean();
			result.setDonorName(donorAward.getDonorAwardDesc());
			String pattern = DateUtil2.DEFAULT_PATTERN;
			result.setFormattedStartDate(DateUtil2.INSTANCE.formatDate(pattern, donorAward.getStartDate()));
			result.setFormattedEndDate(DateUtil2.INSTANCE.formatDate(pattern, donorAward.getEndDate()));
			result.setDonorFiscalYear(donorAward.getFiscalyear());
			result.setDonorDirectFunds(donorAward.getDirectFunds());
		}
		return result;
	}

	public List<Donoraward> getActiveDonoraward() {
		List<Donoraward> donorawards = new ArrayList<Donoraward>();
		try {
			Donorawardstatus status = this.donorawardstatusService.findByDisplayName(Constants.Active);
			String query = "from Donoraward where" + Util.createFirstQueryClause(status);
			donorawards = this.dao.getResultList(query);
		} catch (Exception exp) {
			logger.error(exp.getMessage(), exp);
		}
		return donorawards;
	}

	public List<Donoraward> getDonorawardByDonorawardNumberOrByDonor(String donorawardNumber, int donorId) {
		Donor donor = donorService.findById(donorId);
		Object[] params = new Object[2];
		if (StringUtils.isNotBlank(donorawardNumber)) {
			params[0] = donorawardNumber;
		} else {
			params[0] = "%";
		}
		if (donor != null) {
			params[1] = donor;
		} else {
			params[1] = "%";
		}
		List<Donoraward> donorawardList = new ArrayList<Donoraward>();
		try {
			donorawardList = dao.getNamedQueryResultList("getDonorawardByDonorawardNumberOrByDonor", params);
		} catch (Exception exp) {
			logger.warn(exp.toString());
		}
		return donorawardList;
	}

	public Donoraward saveDonoraward(Donoraward donoraward, Integer userId) throws NonUniqueDonorAwardNumberException {
		if (donoraward != null) {
			// if
			// (findDonorawardByDonorAwardNumber(donoraward.getDonorAwardNumber()).size()
			// > 0) {
			// throw new NonUniqueDonorAwardNumberException();
			// }
			User user = userService.findById(userId);
			Donoraward dbDonoraward = findById(donoraward.getId());
			if (dbDonoraward == null) {
				dbDonoraward = new Donoraward();
				dbDonoraward.setCreatedBy(user);
				dbDonoraward.setCreationDate(DateUtil.getCurrentDate());
			} else {
				saveDonorawardmodification(dbDonoraward, donoraward, user);
			}
			dbDonoraward.setDonorAwardNumber(donoraward.getDonorAwardNumber());
			dbDonoraward.setDonor(donoraward.getDonor());
			dbDonoraward.setDonorAwardDesc(donoraward.getDonorAwardDesc());
			dbDonoraward.setStartDate(donoraward.getStartDate());
			dbDonoraward.setEndDate(donoraward.getEndDate());
			dbDonoraward.setDirectFunds(donoraward.getDirectFunds());
			dbDonoraward.setIndirectFunds(donoraward.getIndirectFunds());
			BigDecimal obligatedAmount = new BigDecimal(0).add(donoraward.getDirectFunds()).add(donoraward.getIndirectFunds());
			dbDonoraward.setObligatedAmount(obligatedAmount);
			dbDonoraward.setDonorawardstatus(donoraward.getDonorawardstatus());
			dbDonoraward.setDonorawardtype(donoraward.getDonorawardtype());
			dbDonoraward.setFiscalyear(donoraward.getFiscalyear());
			dbDonoraward.setAttachment(donoraward.getAttachment());
			dbDonoraward.setAttachmentName(donoraward.getAttachmentName());
			dbDonoraward.setMemonotes(donoraward.getMemonotes());
			/*
			 * dbDonoraward.setAttachmentContentType(donoraward.
			 * getAttachmentContentType());
			 * dbDonoraward.setAttachmentName(donoraward.getAttachmentName());
			 * dbDonoraward.setCity(donoraward.getCity());
			 * dbDonoraward.setState(donoraward.getState());
			 */dbDonoraward.setUpdatedBy(user);
			dbDonoraward.setUpdationDate(DateUtil.getCurrentDate());
			return merge(dbDonoraward);
		}
		return null;
	}

	private void saveDonorawardmodification(Donoraward dbDonorAward, Donoraward bean, User user) {
		List<Donorawardmodification> list = new ArrayList<Donorawardmodification>();
		if (!DateUtil2.INSTANCE.isSameDay(dbDonorAward.getStartDate(), bean.getStartDate())) {
			Donorawardmodification modification = createDonorAwardModication(dbDonorAward, bean, user);
			Modificationtype type = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.startDate"));
			modification.setModificationType(type);
			modification.setModifiedFrom(DateUtil2.INSTANCE.formatDate(dbDonorAward.getStartDate()));
			modification.setModifiedTo(DateUtil2.INSTANCE.formatDate(bean.getStartDate()));
			list.add(modification);
		}

		if (!DateUtil2.INSTANCE.isSameDay(dbDonorAward.getEndDate(), bean.getEndDate())) {
			Donorawardmodification modification = createDonorAwardModication(dbDonorAward, bean, user);
			Modificationtype modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.endDate"));
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(DateUtil2.INSTANCE.formatDate(dbDonorAward.getEndDate()));
			modification.setModifiedTo(DateUtil2.INSTANCE.formatDate(bean.getEndDate()));
			list.add(modification);
		}

		if (dbDonorAward.getDirectFunds() == null && bean.getDirectFunds() != null || !dbDonorAward.getDirectFunds().equals(bean.getDirectFunds())) {
			Donorawardmodification modification = createDonorAwardModication(dbDonorAward, bean, user);
			Modificationtype modificationType = null;
			if (dbDonorAward.getDirectFunds().compareTo(bean.getDirectFunds()) < 0) {
				modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.directfunds.increased"));
			} else {
				modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.directfunds.reduced"));
			}
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(dbDonorAward.getDirectFunds().toPlainString());
			modification.setModifiedTo(bean.getDirectFunds().toPlainString());
			list.add(modification);
		}

		if (dbDonorAward.getIndirectFunds() == null && bean.getIndirectFunds() != null || dbDonorAward.getIndirectFunds().compareTo(bean.getIndirectFunds()) != 0) {
			Donorawardmodification modification = createDonorAwardModication(dbDonorAward, bean, user);
			Modificationtype modificationType = null;
			if (dbDonorAward.getIndirectFunds().compareTo(bean.getIndirectFunds()) < 0) {
				modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.indirectfunds.increased"));
			} else {
				modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.indirectfunds.reduced"));
			}
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(dbDonorAward.getIndirectFunds().toPlainString());
			modification.setModifiedTo(bean.getIndirectFunds().toPlainString());
			list.add(modification);
		}
		
        Integer prevStatusId = dbDonorAward.getDonorawardstatus() != null ? dbDonorAward.getDonorawardstatus().getId() : null;
        Integer currStatusId = bean.getDonorawardstatus() != null ? bean.getDonorawardstatus().getId() : null;

        if (!NumberUtil.INSTANCE.isEqual(prevStatusId, currStatusId)) {
			Donorawardmodification modification = createDonorAwardModication(dbDonorAward, bean, user);
			Modificationtype modificationType = modificationTypeService.getModificationTypeByCodeOrName(getText("code.modificationType.changed.status"));
			modification.setModificationType(modificationType);
			modification.setModifiedFrom(dbDonorAward.getDonorawardstatus().getDisplayName());
            if (currStatusId != null && currStatusId > 0) {
                Donorawardstatus newStatus = donorawardstatusService.findById(bean.getDonorawardstatus().getId());
                modification.setModifiedTo(newStatus.getDisplayName());
            } else {
                modification.setModifiedTo("");
            }
			list.add(modification);
		}

		if (!list.isEmpty()) {
			List<Donorawardmodification> modifications = dbDonorAward.getDonorawardmodifications();
			if (modifications == null) {
				dbDonorAward.setDonorawardmodifications(list);
			} else {
				modifications.addAll(list);
			}
		}
	}

	private Donorawardmodification createDonorAwardModication(Donoraward dbDonorAward, Donoraward bean, User user) {
		Donorawardmodification modification = new Donorawardmodification();
		Date currentDate = new Date();
		modification.setCreatedBy(user);
		modification.setCreationDate(currentDate);
		modification.setModifiedBy(user);
		modification.setModifiedDate(currentDate);
		modification.setDonoraward(dbDonorAward);
		modification.setAttachment(bean.getModificationDocumentLocation());
		return modification;
	}
}
